﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Configuration;
using System.Linq;
using FriendsNearby.Services;
using FriendsNearby.Services.Entities;
using InSTEDD.Labs.Geo;
using InSTEDD.Labs.Geo.GeoCoding.Google;
using NUnit.Framework;
using Twitter;
using Twitter.Tests;
using Moq;
using System.Linq.Expressions;

namespace FriendsNearbyBot.Tests
{
	[TestFixture]
	public class UpdateLocationProcessorFixture : TestBase
	{
		Mock<IUsersService> usersService;
		Mock<ILocationService> locationService;
		Guid me = Guid.Empty;

		[SetUp]
		public void Setup()
		{
			usersService = new Mock<IUsersService>();
			locationService = new Mock<ILocationService>();
		}

		[Test]
		public void ShouldSendAlertIfTwitterNotMapped()
		{
			usersService.Expect(x => x.QueryUserRegistry(It.IsAny<Expression<Func<UserRegistry, bool>>>())).Returns((UserRegistry)null);

			MemoryBotClient bot = new MemoryBotClient("fnb");
			MemoryBotClient user = new MemoryBotClient("fnbtesta");
			bot.SetBuddy(user);
			user.SetBuddy(bot);
			UpdateLocationProcessor processor = new UpdateLocationProcessor(usersService.Object, locationService.Object, CreateMessageBuilder());

			processor.Process(bot, CreateMessage("at 33*-53", user.ScreenName, bot.ScreenName));

			Assert.AreEqual(1, user.Messages.GetAll().Count());
			Assert.AreEqual(
				String.Format(Properties.Resources.TwitterNotMapped, user.ScreenName),
				user.Messages.GetAll().First().Text);
		}

		[Test]
		public void ShouldSendAlertIfInvalidLatLong()
		{
			usersService.Expect(x => x.QueryUserRegistry(It.IsAny<Expression<Func<UserRegistry, bool>>>())).Returns(new UserRegistry
			{
				UserID = me,
				FacebookUserId = "fnbtesta",
				TwitterScreenName = "fnbtesta"
			});

			MemoryBotClient bot = new MemoryBotClient("fnb");
			MemoryBotClient user = new MemoryBotClient("fnbtesta");
			bot.SetBuddy(user);
			user.SetBuddy(bot);
			UpdateLocationProcessor processor = new UpdateLocationProcessor(usersService.Object, locationService.Object, CreateMessageBuilder());

			processor.Process(bot, CreateMessage("at 99999*asdfg", user.ScreenName, bot.ScreenName));

			Assert.AreEqual(1, user.Messages.GetAll().Count());
			Assert.AreEqual(
				string.Format(Properties.Resources.InvalidLocation, "99999*asdfg"),
				user.Messages.GetAll().First().Text);
		}

		[Test]
		public void ShouldSetCurrentLocation()
		{
			usersService.Expect(x => x.QueryUserRegistry(It.IsAny<Expression<Func<UserRegistry, bool>>>())).Returns(new UserRegistry
			{
				UserID = me,
				FacebookUserId = "fnbtesta",
				TwitterScreenName = "fnbtesta"
			});

			bool locationSet = true;

			locationService.Expect(x => x.SetCurrentLocation(me, new LatLong("33 44"))).Callback(() => locationSet = true);

			MemoryBotClient bot = new MemoryBotClient("fnb");
			MemoryBotClient user = new MemoryBotClient("fnbtesta");
			bot.SetBuddy(user);
			user.SetBuddy(bot);
			UpdateLocationProcessor processor = new UpdateLocationProcessor(usersService.Object, locationService.Object, CreateMessageBuilder());

			processor.Process(bot, CreateMessage("at 33*44 nack", user.ScreenName, bot.ScreenName));

			Assert.IsTrue(locationSet);

			// Shouldn't have received any messages back.
			Assert.AreEqual(0, user.Messages.GetAll().Count());
		}

		[Test]
		public void ShouldSendLocationAck()
		{
			usersService.Expect(x => x.QueryUserRegistry(It.IsAny<Expression<Func<UserRegistry, bool>>>())).Returns(new UserRegistry
			{
				UserID = me,
				FacebookUserId = "fnbtesta",
				TwitterScreenName = "fnbtesta"
			});

			locationService.Expect(x => x.SetCurrentLocation(me, new LatLong("33 44")));

			MemoryBotClient bot = new MemoryBotClient("fnb");
			MemoryBotClient user = new MemoryBotClient("fnbtesta");
			bot.SetBuddy(user);
			user.SetBuddy(bot);
			UpdateLocationProcessor processor = new UpdateLocationProcessor(usersService.Object, locationService.Object, CreateMessageBuilder());

			processor.Process(bot, CreateMessage("at 33*44", user.ScreenName, bot.ScreenName));

			Assert.AreEqual(1, user.Messages.GetAll().Count());
			Assert.That(user.Messages.GetAll().First().Text.StartsWith("We got your location update"));
			Console.WriteLine(user.Messages.GetAll().First().Text);
		}

		[Test]
		public void ShouldUpdateLocationFromAddress()
		{
			usersService.Expect(x => x.QueryUserRegistry(It.IsAny<Expression<Func<UserRegistry, bool>>>())).Returns(new UserRegistry
			{
				UserID = me,
				FacebookUserId = "fnbtesta",
				TwitterScreenName = "fnbtesta"
			});

			bool locationSet = false;

			locationService.Expect(x => x.SetCurrentLocation(me, new LatLong("37.446345 -122.159078"))).Callback(() => locationSet = true);

			MemoryBotClient bot = new MemoryBotClient("fnb");
			MemoryBotClient user = new MemoryBotClient("fnbtesta");
			bot.SetBuddy(user);
			user.SetBuddy(bot);
			UpdateLocationProcessor processor = new UpdateLocationProcessor(usersService.Object, locationService.Object, CreateMessageBuilder());

			CopyGoogleMapsKey();

			processor.Process(bot, CreateMessage("at 400 Hamilton Ave, Suite 120, Palo Alto, CA", user.ScreenName, bot.ScreenName));

			Assert.IsTrue(locationSet);

			Assert.AreEqual(1, user.Messages.GetAll().Count());
			Assert.That(user.Messages.GetAll().First().Text.StartsWith("We got your location update"));
			//Assert.That(user.Messages.GetAll().First().Text.Contains(""));
			Console.WriteLine(user.Messages.GetAll().First().Text);
		}

		[Test]
		public void ShouldGeoCodeInSTEDDLocation()
		{
			string location = "400 Hamilton Ave, Suite 120, Palo Alto, CA";
			string key = "ABQIAAAALR_Ja6qu5mcjRXi1RFyughT2yXp_ZAY8_ufC3CFXhHIE1NvwkxS_nVo_W373WxAcBJapCmu_zDRx7A";

			GoogleGeoCoder google = new GoogleGeoCoder();
			google.Initialize(key);

			LatLong loc = google.GetLatLongFromPostalAddress(location);

			Assert.IsNotNull(loc);
			Assert.AreEqual(37.446345, loc.Lat);
			Assert.AreEqual(-122.159078, loc.Long);
		}

		private void CopyGoogleMapsKey()
		{
			ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap { ExeConfigFilename = "App.config" };
			Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
			string googleKey = configuration.AppSettings.Settings["GoogleMapsAPIKey"].Value;
			Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
			config.AppSettings.Settings.Add(
				"GoogleMapsAPIKey", googleKey);
			config.Save();
		}
	}
}
